package org.springframework.security.web.authentication.rememberme;

import java.util.Arrays;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.util.StringUtils;

import com.nuanshui.heatedloan.constant.GlobalParam;
import com.nuanshui.heatedloan.baseservice.model.UserAgent;
import com.nuanshui.heatedloan.baseservice.model.User;
import com.nuanshui.framework.cache.CacheConstants;
import com.nuanshui.framework.utils.redis.JedisUtil;

/**
 * 先取cookie，没有则尝试从req param里获取authToken。
 * 
 * @author Ju
 */
public class PersistentTokenBasedRememberMeServicesEx extends PersistentTokenBasedRememberMeServices {

    private PersistentTokenRepository tokenRepository = new InMemoryTokenRepositoryImpl();

    @Autowired
    private JedisUtil JedisUtil;
	@SuppressWarnings("deprecation")
	public PersistentTokenBasedRememberMeServicesEx() {
		super();
	}

	public PersistentTokenBasedRememberMeServicesEx(String key, UserDetailsService userDetailsService,
			PersistentTokenRepository tokenRepository) {
		super(key, userDetailsService, tokenRepository);
		this.tokenRepository = tokenRepository;
	}

	@Override
	protected UserDetails processAutoLoginCookie(String[] cookieTokens, HttpServletRequest request,
			HttpServletResponse response) {
		String uri = request.getRequestURI();
	    JedisUtil.hget(CacheConstants.NEED_LOGIN_URL_LIST,uri,String.class);
//		if(!"1".equals(value)) {
//		    response.addHeader("__not_clear_cookies", "true");
//			throw new UsernameNotFoundException("");
//		}
		if (isDeviceToken(cookieTokens)) { // deviceId
			return getUserDetailsService().loadUserByUsername(cookieTokens[1]); // FIXME
		}
		UserAgent userAgent = (UserAgent) request.getAttribute(GlobalParam.USER_AGENT);
		String  safeToken = userAgent.getSafeToken();
		if(safeToken == null) safeToken = "lock";
		UserDetails userDetails = null;
		synchronized (safeToken.intern()) {
			 userDetails = customProcessAutoLoginCookie(cookieTokens, request, response);
		}
		return userDetails;
	}	
	private  UserDetails customProcessAutoLoginCookie(String[] cookieTokens, HttpServletRequest request,
			HttpServletResponse response) {
		 boolean isExe = true;
		if (cookieTokens.length != 2) {
            throw new InvalidCookieException("Cookie token did not contain " + 2 +
                    " tokens, but contained '" + Arrays.asList(cookieTokens) + "'");
        }
        final String presentedSeries = cookieTokens[0];
        final String presentedToken = cookieTokens[1];
        
        PersistentRememberMeToken token = tokenRepository.getTokenForSeries(presentedSeries);
        if (token == null) {
            throw new RememberMeAuthenticationException("No persistent token found for series id: " + presentedSeries);
        }
        if (!presentedToken.equals(token.getTokenValue())) {          
        	//生成新的token的时间超过10秒后报错，主要是为了处理一个客户端同时多个请求，暂时不得一而为之   	
            Long time = new Date().getTime()-token.getDate().getTime();
            if(time>10*1000) {
            	JdbcTokenRepositoryImplEx ex = (JdbcTokenRepositoryImplEx) tokenRepository;
            	ex.remoteBySeries(presentedSeries);
            	logger.error("自动登录token过期");
                throw new RememberMeAuthenticationException("自动 登录token过期");
            }else {
            	isExe = false;
            	response.addHeader("__not_clear_cookies", "true");
            	//throw new UsernameNotFoundException("");
            }
        }
        if(isExe) {
        	if (token.getDate().getTime() + getTokenValiditySeconds()*1000L < System.currentTimeMillis()) {
                throw new RememberMeAuthenticationException("Remember-me login has expired");
            }
            PersistentRememberMeToken newToken = new PersistentRememberMeToken(token.getUsername(),
                    token.getSeries(), generateTokenData(), new Date());
            try {
                tokenRepository.updateToken(newToken.getSeries(), newToken.getTokenValue(), newToken.getDate());
                setCookie(new String[] {newToken.getSeries(), newToken.getTokenValue()}, getTokenValiditySeconds(), request, response);
            } catch (DataAccessException e) {
                logger.error("Failed to update token: ", e);
                throw new RememberMeAuthenticationException("Autologin failed due to data access problem");
            }
        }
        return getUserDetailsService().loadUserByUsername(token.getUsername());
	}
	
	
	private boolean isDeviceToken(String[] cookieTokens) {
		return cookieTokens.length == 3 && "device".equals(cookieTokens[0]);
	}

	/**
	 * 先取cookie，没有则尝试从req param里获取
	 */
	@Override
	protected String extractRememberMeCookie(HttpServletRequest request) {
		String ret = super.extractRememberMeCookie(request);
		if (StringUtils.hasText(ret))
			return ret;
		return request.getParameter(getCookieName());
	}
	
	
	@Override
	protected void onLoginSuccess(HttpServletRequest request,
			HttpServletResponse response,
			Authentication successfulAuthentication) {
        
		String username = successfulAuthentication.getName();

        logger.debug("Creating new persistent login for user " + username);

        PersistentRememberMeToken persistentToken = new PersistentRememberMeToken(username, generateSeriesData(),
                generateTokenData(), new Date());
        try {
            tokenRepository.createNewToken(persistentToken);
            User user = (User) successfulAuthentication.getPrincipal();
            user.setSeries(persistentToken.getSeries());
            setCookie(new String[] {persistentToken.getSeries(), persistentToken.getTokenValue()}, getTokenValiditySeconds(), request, response);
        } catch (DataAccessException e) {
            logger.error("Failed to saveAndPush persistent token ", e);
        }
	}
	
	@Override
	public void logout(HttpServletRequest request,
			HttpServletResponse response, Authentication authentication) {
		  if (authentication != null) {
			  User user = (User) authentication.getPrincipal();
			  JdbcTokenRepositoryImplEx ex = (JdbcTokenRepositoryImplEx) tokenRepository;
	            ex.remoteBySeries(user.getSeries());
	       }
	}

}
